package main

import (
	"fmt"
	"unsafe"
)

func pointerDemo() {
	i := 10
	ip := &i

	//直接将 *int 转换为 *float64 将不被允许
	//var fp = (*float64)(ip)
	//fmt.Println(fp) //cannot convert ip (type *int) to type *float64

	//使用 unsafe.pointer 将  *int 转换为 *float64
	var fp *float64 = (*float64)(unsafe.Pointer(ip))
	*fp = *fp * 3
	fmt.Printf("ip的类型：%T,fp的类型：%T,Value：%v \n", ip, fp, i) //ip的类型：*int,fp的类型：*float64,Value：30

	//通过指针偏移修改Struct内的字段来演示 uintptr 的用法
	type user struct {
		name string
		age  int
	}
	u := &user{}
	fmt.Println(*u) // { 0}
	//获取第一个字段name的地址
	name := (*string)(unsafe.Pointer(u))
	//设置第一个字段name的值
	*name = "张三"
	//获取第一个字段age的地址，涉及到计算内存偏移量
	//先将 *struct 转换为 unsafe.Pointer 通用类型，再转换为 uintptr 可计算类型，随机加上内存偏移量转为 age 字段本身的 *int 进行赋值
	//该表达式不可拆开写，因为如果其中子表达式的临时变量被GC，就会导致内存操作出错，谨慎使用
	age := (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(u)) + unsafe.Offsetof(u.age)))
	*age = 20

	fmt.Println(*u) //{张三 20}
}
